<?php
/**
 * Ganglib
 *
 * LICENSE
 *
 * This source file is subject to the GNU Lesser Generak Public license.
 *
 * It is available through the world-wide-web at this URL:
 * http://www.gnu.org/licenses/lgpl.html
 *
 * @category    Ganglib
 * @package    Div_Session
 * @copyright  Copyright (c) 2008 Ganglib project members (http://www.code.google.com/p/ganglib)
 * @license     http://www.gnu.org/licenses/lgpl.html
 */

/**
 * @see Zend_Cache_Core
 */
require_once 'Zend/Cache/Core.php';

/**
 * @see Zend_Session_SaveHandler_Interface
 */
require_once 'Zend/Session/SaveHandler/Interface.php';


/**
 * session handler
 *
 * example:
 $cache = new Zend_Cache_Core();
 $cache->setBackend(new Zend_Cache_Backend_File());

 $ses_handler = new Div_Session_Memcachedhandler($cache);
 $ses_handler->write('myid','secret name',1000);

 Zend_Session::setSaveHandler($ses_handler);
 Zend_Session::getSaveHandler()->read('myid');
 Zend_Session::getSaveHandler()->gc();
 *
 * @author alex
 * @category    Ganglib
 * @package    Div_Session
 * @copyright  Copyright (c) 2008 Ganglib project members (http://www.code.google.com/p/ganglib)
 * @license     http://www.gnu.org/licenses/lgpl.html
 */
class Div_Session_Memcachedhandler implements Zend_Session_SaveHandler_Interface
{

	/**
	 * constatns
	 */

	// seion table name
	const TABLE_NAME         = 'sessions';

	// prmary key column name
	const COLUMN_PRIMARY_KEY = 'id';

	// lifetime column name
	const COLUMN_LIFETIME    = 'lifetime';

	// data column name
	const COLUMN_DATA        = 'data';

	protected $_maxlifetime = 5400; // 60*90

	/**
	 * primary key
	 * @var string
	 */
	protected $_primary = self::COLUMN_PRIMARY_KEY;

	protected $_dbBackend = true;

	/**
	 * table name
	 * @var string
	 */
	protected $_name = self::TABLE_NAME;

	/**
	 * table columns.
	 * @var array
	 */
	protected $_columnMap = array(
	self::COLUMN_PRIMARY_KEY => self::COLUMN_PRIMARY_KEY,
	self::COLUMN_LIFETIME    => self::COLUMN_LIFETIME,
	self::COLUMN_DATA        => self::COLUMN_DATA
	);

	/**
	 * cache value
	 *
	 * @var Zend_Cache_Core
	 */
	protected $cache;

	/**
	 * Enter description here...
	 *
	 * @param Zend_Cache_Core $cache
	 */
	public function __construct(Zend_Cache_Core $cache, $dbBackend = true)
	{
		$this->_dbBackend = $dbBackend;
		$this->cache = $cache;
	}


	/**
	 * return cache
	 *
	 * @return Zend_Cache_Core
	 */
	public function getCache()
	{
		return $this->cache;
	}

	/**
	 * Open Session - retrieve resources
	 *
	 * @param string $save_path
	 * @param string $name
	 */
	public function open($save_path, $name )
	{
		if( !$this->cache )
		{
			return false;
		}
		return true;
	}
	/**
	 * Close Session - free resources
	 *
	 */
	public function close()
	{
		return true;
	}

	/**
	 * Read session data
	 *
	 * @param string $id
	 * @return mixed $data
	 */
	public function read($id)
	{
		$cachedResult = $this->cache->load($id);
		if(!$cachedResult && $this->_dbBackend)
		{
			require_once('Div/Db/Distributor.php');
			$db = Div_Db_Distributor::getInstance();

			require_once('Div/Db/Query.php');
			$qr = new Div_Db_Query();
			$qr->where($this->_columnMap[self::COLUMN_PRIMARY_KEY], $id)->from($this->_name)->select('*');

			$rowset = $db->query($qr);

			if(isset($rowset[0]))
			{
				$dbResult = $rowset[0][$this->_columnMap[self::COLUMN_DATA]];
				$this->cache->save($dbResult, $id, array(), $this->_maxlifetime); // save for later usage
				return $dbResult;
			}
			else
			return false;
		} else
		return $cachedResult;
	}

	/**
	 * Write Session - commit data to resource
	 *
	 * @param string $id
	 * @param mixed $data
	 * @param int $maxlifetime
	 * @return boolean
	 */
	public function write($id, $data, $maxlifetime = false)
	{

		if($this->_dbBackend)
		{
			$return = false;
			$dataSet = array(
			$this->_columnMap[self::COLUMN_PRIMARY_KEY] => $id,
			$this->_columnMap[self::COLUMN_LIFETIME]    => date("Y-m-d H:i:s", mktime()),
			$this->_columnMap[self::COLUMN_DATA]        => $data
			);

			require_once('Div/Db/Distributor.php');
			$db = Div_Db_Distributor::getInstance();

			require_once('Div/Db/Query.php');
			$qr = new Div_Db_Query();


			$qr->where($this->_columnMap[self::COLUMN_PRIMARY_KEY], $id)->from($this->_name)->select('id');

			$rowset = $db->query($qr);

			$qr->reset();

			if (isset($rowset[0]))
			{
				$qr->where($this->_columnMap[self::COLUMN_PRIMARY_KEY], $id);
				$qr->update($this->_name)->set($dataSet);
			} else {
				$qr->insert($this->_name, $dataSet);
			}

			$return = $db->query($qr);
		}

		$return = $this->cache->save($data, $id, array(), $this->_maxlifetime);

		return $return;
	}

	/**
	 * Destroy Session - remove data from resource for
	 * given session id
	 *
	 * @param string $id
	 * @return boolean
	 */
	public function destroy($id)
	{
		if($this->_dbBackend)
		{
			require_once('Div/Db/Distributor.php');
			$db = Div_Db_Distributor::getInstance();

			require_once('Div/Db/Query.php');
			$qr = new Div_Db_Query();

			$qr->from($this->_name)->where($this->_columnMap[self::COLUMN_PRIMARY_KEY], $id)->delete();
			$db->query($qr);
		}

		return $this->cache->remove($id);
	}

	/**
	 * Garbage Collection - remove old session data older
	 * than $maxlifetime (in seconds)
	 *
	 * @param int $maxlifetime
	 * @return boolean
	 */
	public function gc($maxlifetime)
	{
		if($this->_dbBackend)
		{
			$lifetime = ($this->_lifetime) ? $this->_lifetime : $maxlifetime;
			$expiry = date("Y-m-d H:i:s", mktime() - $lifetime);

			require_once('Div/Db/Distributor.php');
			$db = Div_Db_Distributor::getInstance();
				
			require_once('Div/Db/Query.php');
			$qr = new Div_Db_Query();

			$qr->from($this->_name)->where($this->_columnMap[self::COLUMN_LIFETIME].'<=', $expiry)->delete();
			$result = $db->query($qr);
		}

		$result = $this->cache->clean('old');

		return $result;
	}
}
